#include "detail/box_config_impl.hh"
#include "util/os_util.hh"
#include "../framework/unittest.hh"
#include <fstream>

FIXTURE_BEGIN(test_box_config)

SETUP([]() {
  std::ofstream ofs;
  ofs.open("config.cfg", std::ios::trunc | std::ios::out);
  ofs << "listener = {"
         "   host = (\"127.0.0.1:10001\")"
         "}"
         "service_finder = {"
         "	type = \"test_type\""
         "	hosts = \"10.0.128.214:2181\""
         "}"
         "box_channel_recv_buffer_len = 1024 "
         "box_name = \"test_box\""
         "logger_config_line=\"config_line\""
         "service = {"
         "   service_dir = \"test_dir\""
         "   preload_service = <1:\"1.so\", 2:\"2.so\">"
         "}"
         "value1 = true "
         "value2 = false "
         "connect_other_box_timeout = 2000 "
         "service_finder_connect_timeout = 2000 "
         "open_coroutine = \"false\""
         "test_exp = `(1+2)*3/4`"
         "bool_exp = `true`"
         "str_exp = `\"i'm string\"`"
         "str_com_exp = `\"a\"+\"b\"`"
         "null=``"
         "larger_result=`2>1`"
         "lesser_result=`1<2`"
         "larger_equal=`2>=1`"
         "lesser_equal=`1<=2`"
         "not_equal=`2!=1`"
         "int_mode=`1%10`"
         "logic_add=`(1==1)&&(2==2)`"
         "logic_or = `(\"1\"==\"1\") || (\"1\"!=\"2\")`"
         "uni_excl_mark=`!(1==1) && false`"
         "`1==1` { a = 1 }"
         "`\"1\"==\"2\"` { b = 1 `true`{c=1} }"
         "necessary_service = (\"test\", \"test1\")"
         "array_index=`necessary_service[0]`"
         "array_index1=`necessary_service[1+0]`"
         "table_index=`service.preload_service[\"1\"]`"
         "k = `32*K`";
  ofs.close();

  std::ofstream ofs_new;
  ofs_new.open("config_new.cfg", std::ios::trunc | std::ios::out);
  ofs_new << "listener = {"
             "   host = (\"127.0.0.1:10001\")"
             "}"
             "service_finder = {"
             "	type = \"test_type\""
             "	hosts = \"10.0.128.214:2181\""
             "}"
             "box_channel_recv_buffer_len = 1024 "
             "box_name = \"test_box\""
             "logger_config_line=\"config_new_line\""
             "service = {"
             "   service_dir = \"test_dir\""
             "   preload_service = <1:\"1.so\", 2:\"2.so\">"
             "}"
             "connect_other_box_timeout = 5000 "
             "service_finder_connect_timeout = 2000 "
             "necessary_service = (\"test\", \"test1\")";
  ofs_new.close();
})

CASE(TestConfig1) {
  kratos::config::BoxConfigImpl bc(nullptr);
  std::string error;
  ASSERT_TRUE(bc.load("config.cfg", error));
  ASSERT_TRUE(bc.get_bool("value1"));
  ASSERT_FALSE(bc.get_bool("value2"));
  ASSERT_TRUE(bc.get_box_channel_recv_buffer_len() == 1024);
  ASSERT_TRUE(bc.get_box_name() == "test_box");
  ASSERT_TRUE(bc.get_connect_other_box_timeout() == 2000);
  ASSERT_TRUE(bc.get_listener_list().front() == "127.0.0.1:10001");
  ASSERT_TRUE(bc.get_logger_config_line() == "config_line");
  ASSERT_TRUE(bc.get_service_dir() == "test_dir");
  ASSERT_TRUE(bc.get_service_finder_connect_timeout() == 2000);
  ASSERT_TRUE(bc.get_service_finder_type() == "test_type");
  ASSERT_TRUE(bc.get_service_finder_hosts() == "10.0.128.214:2181");
  ASSERT_TRUE(
      bc.get_preload_service().find("1") != bc.get_preload_service().end() &&
      bc.get_preload_service().find("2") != bc.get_preload_service().end());
  ASSERT_TRUE(bc.get_necessary_service().front() == "test");
  ASSERT_TRUE(!bc.is_open_coroutine());
  ASSERT_TRUE(bc.get_config_ptr()->getInt32("test_exp") == 2);
  ASSERT_TRUE(bc.get_config_ptr()->getBool("bool_exp"));
  ASSERT_TRUE(bc.get_config_ptr()->getString("str_exp") == "i'm string");
  ASSERT_TRUE(bc.get_config_ptr()->getString("str_com_exp") == "ab");
  ASSERT_TRUE(bc.get_config_ptr()->get("null")->isNull());
  ASSERT_TRUE(bc.get_config_ptr()->getBool("larger_result"));
  ASSERT_TRUE(bc.get_config_ptr()->getBool("lesser_result"));
  ASSERT_TRUE(bc.get_config_ptr()->getBool("larger_equal"));
  ASSERT_TRUE(bc.get_config_ptr()->getBool("lesser_equal"));
  ASSERT_TRUE(bc.get_config_ptr()->getBool("not_equal"));
  ASSERT_TRUE(bc.get_config_ptr()->getInt32("int_mode") == 1);
  ASSERT_TRUE(bc.get_config_ptr()->getBool("logic_add"));
  ASSERT_TRUE(bc.get_config_ptr()->getBool("logic_or"));
  ASSERT_TRUE(!bc.get_config_ptr()->getBool("uni_excl_mark"));
  ASSERT_TRUE(bc.get_config_ptr()->getInt32("a") == 1);
  ASSERT_TRUE(!bc.get_config_ptr()->has("b"));
  ASSERT_TRUE(!bc.get_config_ptr()->has("c"));
  ASSERT_TRUE(bc.get_config_ptr()->getString("array_index") == "test");
  ASSERT_TRUE(bc.get_config_ptr()->getString("array_index1") == "test1");
  ASSERT_TRUE(bc.get_config_ptr()->getString("table_index") == "1.so");
  ASSERT_TRUE(bc.get_config_ptr()->getInt32("k") == 1024 * 32);
}

CASE(TestConfig2) {
  kratos::config::BoxConfigImpl bc(nullptr);
  std::string error;
  ASSERT_TRUE(!bc.load("../wrong/config.cfg", error));
}

CASE(TestReload1) {
  kratos::config::BoxConfigImpl bc(nullptr);
  std::string error;
  ASSERT_TRUE(bc.load("config.cfg", error));
  bool call = false;
  bc.add_reload_listener(
      "test", [&](const std::string&, const kratos::config::BoxConfig &) { call = true; });
  ASSERT_TRUE(bc.reload("config_new.cfg", error));
  ASSERT_TRUE(call);
  ASSERT_TRUE(bc.get_connect_other_box_timeout() == 5000);
  ASSERT_TRUE(bc.get_logger_config_line() == "config_new_line");
  ASSERT_TRUE(bc.remove_reload_listener("test"));
}

CASE(TestReload2) {
  kratos::config::BoxConfigImpl bc(nullptr);
  std::string error;
  ASSERT_TRUE(bc.load("config.cfg", error));
  ASSERT_TRUE(nullptr != bc.get_config_ptr());
  bool call = false;
  bc.add_reload_listener(
      "test", [&](const std::string&,const kratos::config::BoxConfig &) { call = true; });
  ASSERT_TRUE(!bc.reload("wrong_config.cfg", error));
  ASSERT_TRUE(!call);
  ASSERT_TRUE(bc.get_connect_other_box_timeout() == 2000);
  ASSERT_TRUE(bc.get_logger_config_line() == "config_line");
}

TEARDOWN([]() {
  kratos::util::remove_file("config.cfg");
  kratos::util::remove_file("config_new.cfg");
})

FIXTURE_END(test_box_config)
